package com.apobates.forum.toro.template;

import com.apobates.forum.toro.core.BeanParser;
import com.apobates.forum.toro.core.Corner;
import com.apobates.forum.toro.core.Express;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 模板属性句语
 * @author xiaofanku@live.cn
 * @since 2022-09-03
 */
public class TemplateStatements{
    /**
     * 查询表达式集合
     * key = 目标对象的类名, value对象中属性的映射
     * 例: Members
     */
    private final String names;
    /**
     * 选择对象的哪个属性可以关联目标对象实例
     * 例: Orders.memberId
     */
    private final String joinAttr;
    /**
     * 聚合对像中哪个属性与joinAttr连接
     */
    private final String linkAttr;
    // 聚合对象属性的类型,必须和joinAttr具有同类型
    // private final String linkAttrType;

    private Set<TemplateExpression> arguments;
    private final static BeanParser<TemplateExpression.Builder> parser;
    static {
        // targetAttr=select(selectAttr:selectAttrTypeName)
        Express exp = Express.getInstance()
                .word("targetAttr")
                .corner(Corner.sequence(0).edge("=select(").build())
                .word("selectAttr")
                .corner(Corner.sequence(1).edge(":").build())
                .word("selectAttrTypeName")
                .corner(Corner.sequence(2).require(false).give("long").edge(")").build());
        // 从表达式到实例
        parser = exp.build(TemplateExpression.Builder.class);
    }
    /**
     * TemplateStatements构造函数
     * @param tag 标签名，用于分组不同的聚合字段属于哪个类。例: Members
     * @param joinAttr 选择对象的类名的连接属性，例:memberId; Orders.memberId( = Member.id)
     */
    public TemplateStatements(String tag, String joinAttr) {
        this.names = tag;
        this.joinAttr = joinAttr;
        this.linkAttr = "id";
        this.arguments = new HashSet<>();
    }

    /**
     * TemplateStatements构造函数
     * @param tag 标签名，用于分组不同的聚合字段属于哪个类。例: Members
     * @param joinAttr 选择对象的类名的连接属性，例:memberId; Orders.memberId( = Member.id)
     * @param linkAttr 命中对象集合中元素的连接属性，例:id; on Orders.memberId = Member.id
     */
    public TemplateStatements(String tag, String joinAttr, String linkAttr) {
        this.names = tag;
        this.joinAttr = joinAttr;
        this.linkAttr = linkAttr;
        this.arguments = new HashSet<>();
    }

    /**
     * TemplateStatements构造函数
     * @param tag 标签名，用于分组不同的聚合字段属于哪个类。例: Members
     * @param joinAttr 选择对象的类名的连接属性，例:memberId; Orders.memberId( = Member.id)
     * @param linkAttr 命中对象集合中元素的连接属性，例:id; on Orders.memberId = Member.id
     * @param arguments 聚合的属性表达式集合
     */
    private TemplateStatements(String tag, String joinAttr, String linkAttr, Set<TemplateExpression> arguments) {
        this.names = tag;
        this.joinAttr = joinAttr;
        this.linkAttr = linkAttr;
        this.arguments = arguments;
    }

    /**
     * 设置模板语句表达式实例
     * 通过TemplateExpression设置关联属性。注意：不要与expr混用
     *
     * @param expression 模板语句表达式
     * @return 属性表达式语句
     */
    public TemplateStatements field(TemplateExpression expression) {
        this.getArguments().add(expression);
        return new TemplateStatements(getNames(), getJoinAttr(), getLinkAttr(), getArguments());
    }

    /**
     * 设置语句表达式描述
     * 通过描述字符串设置关联属性。注意：不要与field混用
     * 格式: targetAttr=select(selectAttr:selectAttrTypeName)
     * @param exprDescribe 模板语句表达式描述
     * @return
     */
    public TemplateStatements expr(String exprDescribe) {
        // targetAttr=select(selectAttr:selectAttrTypeName)
        Map<String,Object> argMap = parser.toMap(exprDescribe);
        TemplateExpression expression = TemplateExpression.Builder
                .newInstance()
                .target(argMap.get("targetAttr").toString())
                .used(argMap.get("selectAttr").toString())
                .usedType(argMap.get("selectAttrTypeName").toString())
                .build();
        this.getArguments().add(expression);
        return new TemplateStatements(getNames(), getJoinAttr(), getLinkAttr(), getArguments());
    }

    /**
     * 创建一个模板属性前缀语句
     * @param affixChars 关联对象属性前缀
     * @return
     */
    public TemplateAffixStatements affix(String affixChars){
        // TemplateAffixStatements(String names, String joinAttr, String linkAttr, String affix)
        return new TemplateAffixStatements(this.names, this.joinAttr, this.linkAttr, affixChars);
    }

    public Set<TemplateExpression> getArguments() {
        return arguments;
    }

    public String getNames() {
        return names;
    }

    public String getJoinAttr() {
        return joinAttr;
    }

    public String getLinkAttr() {
        return linkAttr;
    }
}
